/*
 * mcs.c : uRobot Motion Controller Service.
 * Originally developped for the uRobot project.
 * Parts of the code are originated from GMediaServer from Oskar Liljeblad.
 * Copyright (C) 2011-2012 Seong-Woo Kim <libero@deu.ac.kr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <stdlib.h>
#include <upnp/upnp.h>
#include <upnp/upnptools.h>

#include "urobot.h"
#include "services.h"
#include "mime.h"
#include "target.h"

/* Represent the MCS GoForward action. */
#define SERVICE_MCS_ACTION_GO_FORWARD "GoForward"

/* Represent the MCS GoBackward action. */
#define SERVICE_MCS_ACTION_GO_BACKWARD "GoBackward"

/* Represent the MCS Stop action. */
#define SERVICE_MCS_ACTION_STOP "Stop"

/* Represent the MCS TurnLeft action. */
#define SERVICE_MCS_ACTION_TURN_LEFT "TurnLeft"

/* Represent the MCS TurnRight action. */
#define SERVICE_MCS_ACTION_TURN_RIGHT "TurnRight"

/* Represent the MCS GetCurrentMotionInfo action. */
#define SERVICE_MCS_ACTION_GET_MOTION_INFO "GetMotionInfo"

/* Represent the MCS Command argument. */
#define SERVICE_MCS_ARG_COMMAND "Command"

/* Represent the MCS Status argument. */
#define SERVICE_MCS_ARG_STATUS "Status"

/* Represent the MCS Status value. */
#define SERVICE_MCS_STATUS_OK "OK"

/* Represent the MCS MotionID argument. */
#define SERVICE_MCS_ARG_MOTION_ID "MotionID"

/* Represent the MCS Direction argument. */
#define SERVICE_MCS_ARG_DIRECTION "Direction"

/* Represent the MCS default connection ID value. */
#define SERVICE_MCS_DEFAULT_MOTION_ID "0"

/* Represent the MCS unknown connection ID value. */
#define SERVICE_MCS_UNKNOW_ID "-1"

/* Represent the MCS Output value. */
#define SERVICE_MCS_OUTPUT "Output"

static bool
mcs_go_forward (struct action_event_t *event)
{
  int command;

  if (!event)
    return false;

  /* Retrieve GoForward arguments */
  command = upnp_get_ui4 (event->request, SERVICE_MCS_ARG_COMMAND);

  // make action to go forward the car
  set_motion(FORWARD_MOTION, command);

  upnp_add_response (event, SERVICE_MCS_ARG_STATUS, SERVICE_MCS_STATUS_OK);

  return event->status;
}

static bool
mcs_go_backward (struct action_event_t *event)
{
  int command;

  if (!event)
    return false;

  /* Retrieve GoBackward arguments */
  command = upnp_get_ui4 (event->request, SERVICE_MCS_ARG_COMMAND);

  // make action to go backward the car
  set_motion(BACKWARD_MOTION, command);

  upnp_add_response (event, SERVICE_MCS_ARG_STATUS, SERVICE_MCS_STATUS_OK);

  return event->status;
}

static bool
mcs_stop (struct action_event_t *event)
{
  int command;

  if (!event)
    return false;

  /* Retrieve Stop arguments */
  command = upnp_get_ui4 (event->request, SERVICE_MCS_ARG_COMMAND);

  // make action to stop the car
  set_motion(STOP_MOTION, command);

  upnp_add_response (event, SERVICE_MCS_ARG_STATUS, SERVICE_MCS_STATUS_OK);

  return event->status;
}

static bool
mcs_turn_left (struct action_event_t *event)
{
  int command;

  if (!event)
    return false;

  /* Retrieve TurnLeft arguments */
  command = upnp_get_ui4 (event->request, SERVICE_MCS_ARG_COMMAND);

  // make action to turn left the car
  set_motion(LEFTTURN_MOTION, command);

  upnp_add_response (event, SERVICE_MCS_ARG_STATUS, SERVICE_MCS_STATUS_OK);

  return event->status;
}

static bool
mcs_turn_right (struct action_event_t *event)
{
  int command;

  if (!event)
    return false;

  /* Retrieve TurnRight arguments */
  command = upnp_get_ui4 (event->request, SERVICE_MCS_ARG_COMMAND);

  // make action to turn right the car
  set_motion(RIGHTTURN_MOTION, command);

  upnp_add_response (event, SERVICE_MCS_ARG_STATUS, SERVICE_MCS_STATUS_OK);

  return event->status;
}

static bool
mcs_get_current_motion_info (struct action_event_t *event)
{
  if (!event)
    return false;

  upnp_add_response (event, SERVICE_MCS_ARG_MOTION_ID,
                     SERVICE_MCS_DEFAULT_MOTION_ID);

  upnp_add_response (event, SERVICE_MCS_ARG_DIRECTION, SERVICE_MCS_OUTPUT);
  upnp_add_response (event, SERVICE_MCS_ARG_STATUS, SERVICE_MCS_STATUS_OK);

  return event->status;
}

/* List of UPnP ConnectionManager Service actions */
struct service_action_t mcs_service_actions[] = {
  { SERVICE_MCS_ACTION_GO_FORWARD, mcs_go_forward },
  { SERVICE_MCS_ACTION_GO_BACKWARD, mcs_go_backward },
  { SERVICE_MCS_ACTION_STOP, mcs_stop },
  { SERVICE_MCS_ACTION_TURN_LEFT, mcs_turn_left },
  { SERVICE_MCS_ACTION_TURN_RIGHT, mcs_turn_right },
  { SERVICE_MCS_ACTION_GET_MOTION_INFO, mcs_get_current_motion_info },
  { NULL, NULL }
};
